package cn.lg.soar.mvc.controller;

import cn.lg.soar.common.annotations.DictDefine;
import cn.lg.soar.common.data.dict.DictItem;
import cn.lg.soar.common.data.dict.IDict;
import cn.lg.soar.common.util.EnumUtils;
import cn.lg.soar.common.util.data.StringUtil;
import cn.lg.soar.common.util.reflect.ClassUtils;
import cn.lg.soar.common.util.trans.handler.AbstractDictTranslateHandler;
import cn.lg.soar.core.annotations.ApiClient;
import cn.lg.soar.core.annotations.DataScope;
import cn.lg.soar.core.api.IResourceApi;
import cn.lg.soar.core.dto.SysDict;
import cn.lg.soar.core.enums.LoggerLevelEnum;
import cn.lg.soar.core.model.DataScopeInfo;
import cn.lg.soar.core.util.LoggerUtils;
import cn.lg.soar.mvc.util.RequestMappingUtils;
import io.swagger.v3.oas.annotations.Hidden;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.lang.reflect.Method;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author luguoxiang 469599794@qq.com
 * @Date: 2023/9/30 23:33
 * 开源项目：https://gitee.com/lgx1992/lg-soar 求star！请给我star！请帮我点个star！
 */
@Hidden
@ApiClient("boot")
@Tag(name = "资源服务")
@RestController
public class ResourceApiController {
    private static final Logger LOGGER = LoggerFactory.getLogger(ResourceApiController.class);

    @Value("${lg.enum-packages:cn.lg.**.enums}")
    private String packages;

    private final ApplicationContext applicationContext;

    private final Map<String, AbstractDictTranslateHandler> translateHandlerMap;

    public ResourceApiController(ApplicationContext applicationContext, List<AbstractDictTranslateHandler> dictTranslateHandlers) {
        this.applicationContext = applicationContext;
        this.translateHandlerMap = dictTranslateHandlers.stream()
                .collect(Collectors.toMap(AbstractDictTranslateHandler::getCode, x -> x));
    }

    @Operation(summary = "所有接口")
    @GetMapping(IResourceApi.ALL_PATH)
    public Map<String, String> getAllPath() {
        LOGGER.debug("扫描服务所有接口");
        return RequestMappingUtils.getAllMappingPath();
    }

    @GetMapping(IResourceApi.ALL_DATA_SCOPE_INFO)
    public Map<String, DataScopeInfo> getAllDataScopeInfo() {
        String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
        Map<String, DataScopeInfo> map = new HashMap<>();
        for (String beanName : beanDefinitionNames) {
            Object bean = applicationContext.getBean(beanName);
            Class<?> targetClass = AopUtils.getTargetClass(bean);
            Method[] methods = targetClass.getDeclaredMethods();
            for (Method method : methods) {
                if (method.isAnnotationPresent(DataScope.class)) {
                    DataScope dataScope = method.getAnnotation(DataScope.class);
                    map.put(dataScope.code(), new DataScopeInfo(dataScope));
                }
            }
        }
        return map;
    }

    @Operation(summary = "获取系统配置的字典")
    @GetMapping(IResourceApi.SYS_DICT)
    public IDict<Integer>[] getSysDict(@RequestParam(name = "code", required = false) String code) {
        LOGGER.debug("查找服务系统配置的字典：{}", code);
        AbstractDictTranslateHandler dictTranslateHandler = translateHandlerMap.get(code);
        if (dictTranslateHandler != null) {
            return dictTranslateHandler.dicts();
        }
        return toArray(
                EnumUtils.scanToDictEnum(packages, code)
        );
    }

    @Operation(summary = "获取所有系统配置的字典")
    @GetMapping(IResourceApi.ALL_SYS_DICT)
    public List<SysDict<Integer>> getAllSysDict() {
        LOGGER.debug("扫描服务所有系统配置的字典");
        List<SysDict<Integer>> list = new ArrayList<>(128);
        ClassUtils.scan(this.packages, (x) -> {
            if (!x.isEnum() || !IDict.class.isAssignableFrom(x)) {
                return;
            }
            DictDefine dictDefine = x.getAnnotation(DictDefine.class);
            if (dictDefine == null) {
                return;
            }
            String code = StringUtil.isBlank(dictDefine.code()) ? x.getSimpleName() : dictDefine.code();
            String name = StringUtil.isBlank(dictDefine.name()) ? x.getSimpleName() : dictDefine.name();
            IDict[] dicts = ((Class<IDict>) x).getEnumConstants();
            SysDict<Integer> enumDict = new SysDict<>();
            enumDict.setCode(code);
            enumDict.setName(name);
            enumDict.setDicts(toArray(dicts));
            list.add(enumDict);
        });
        translateHandlerMap.forEach((code, v) -> {
            SysDict<Integer> enumDict = new SysDict<>();
            enumDict.setCode(code);
            enumDict.setName(v.getName());
            enumDict.setDicts(v.dicts());
            list.add(enumDict);
        });
        return list;
    }

    @Operation(summary = "获取系统枚举")
    @GetMapping(IResourceApi.ENUMS)
    public Map<String, IDict<?>[]> getEnums(@RequestParam(name = "names", required = false) String[] names) {
        LOGGER.debug("查找服务系统枚举：{}", names);
        Map<String, IDict<?>[]> map = EnumUtils.scanToArrays(this.packages, names);
        map.forEach((k, v) -> {
            map.put(k, toArray(v));
        });
        return map;
    }

    @Operation(summary = "获取日志级别")
    @GetMapping(IResourceApi.GET_LOGGER_LEVEL)
    public LoggerLevelEnum getLoggerLevel(@RequestParam("loggerName") String loggerName) {
        return LoggerUtils.getLevel(loggerName);
    }

    @Operation(summary = "设置日志级别")
    @GetMapping(IResourceApi.SET_LOGGER_LEVEL)
    public LoggerLevelEnum setLoggerLevel(@RequestParam("loggerName") String loggerName, @RequestParam("level") LoggerLevelEnum level) {
        return LoggerUtils.setLevel(loggerName, level);
    }

    @Operation(summary = "设置日志级别")
    @GetMapping(IResourceApi.CHANGE_SQL_LOGGER)
    public void changeSqlLogger(@RequestParam("enabled") boolean enabled) {
        if (enabled) {
            LoggerUtils.openSqlLog();
        } else {
            LoggerUtils.closeSqlLog();
        }
    }

    private IDict<Integer>[] toArray(IDict[] dicts) {
        return Arrays.stream(dicts).map(d -> new DictItem<>(d.getValue(), d.getLabel())).toArray(IDict[]::new);
    }

}
